/*
 * Copyright (c) 2009, Hamish Morgan. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the University of Sussex nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package locusts.client.renderer;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import javax.imageio.ImageIO;
import locusts.common.Constants;
import locusts.common.World;
import locusts.common.entities.Entity;
import locusts.common.entities.EntityList;
import locusts.common.entities.EntityTypeList;
import locusts.lib.geom.Triangle;

/**
 *
 * @author Hamish Morgan
 */
public class EntityListRenderer {

    private World world;
    //
    Map<Integer, EntityRenderer> renderers;
    EntityRenderer defaultRenderer;

    public EntityListRenderer(World world) {
        this.world = world;

        defaultRenderer = new BasicEntityRenderer();

        renderers = new HashMap<Integer, EntityRenderer>();

    }

    private void initialize() {

        final EntityTypeList types = world.getTypes();
        if (types.containsName(Constants.WALL)) {
            final int id = types.getName(Constants.WALL).getId();
            if (!renderers.containsKey(id))
                renderers.put(id, makeWallRenderer());
        }

        if (types.containsName(Constants.LOCUST)) {
            final int id = types.getName(Constants.LOCUST).getId();
            if (!renderers.containsKey(id))
                renderers.put(id, makeLocustRenderer());

//            ((AnimationRenderer) renderers.get(id)).incrementFrame();
        }

        if (types.containsName(Constants.DEAD_LOCUST)) {
            final int id = types.getName(Constants.DEAD_LOCUST).getId();
            if (!renderers.containsKey(id)) {
                EntityRenderer r = makeDeadLocustRenderer();
//                r.setShowEnergy(true);
                renderers.put(id, r);
            }
        }

        if (types.containsName(Constants.FARM)) {
            final int id = types.getName(Constants.FARM).getId();
            if (!renderers.containsKey(id))
                renderers.put(id, new FarmRenderer());
        }

        if (types.containsName(Constants.CROPS)) {
            final int id = types.getName(Constants.CROPS).getId();
            if (!renderers.containsKey(id))
                renderers.put(id, new CropPileRenderer());
        }

        if (types.containsName(Constants.MOUSE_MOVE)) {
            final int id = types.getName(Constants.MOUSE_MOVE).getId();
            if (!renderers.containsKey(id))
                renderers.put(id, makeMouseRenderer());
        }

        if (types.containsName(Constants.MOUSE_DOWN)) {
            final int id = types.getName(Constants.MOUSE_DOWN).getId();
            if (!renderers.containsKey(id))
                renderers.put(id, makeMouseRenderer());
        }

    }

    public void render(Graphics2D g) {
        initialize();

        final EntityList ents = world.getEntities();
        if (ents.size() == 0)
            return;
        Queue<Entity> queue = new PriorityQueue<Entity>(ents.size(),
                new Comparator<Entity>() {

                    public int compare(Entity o1, Entity o2) {
                        int zdiff = o1.getzOrder() - o2.getzOrder();
                        if (zdiff != 0) return zdiff;
                        return o2.getId() - o1.getId();
                    }
                });
        queue.addAll(ents);

        while (!queue.isEmpty()) {
            Entity e = queue.poll();
//        }
//
//        for (Entity e : ents) {

            if (renderers.containsKey(e.getTypeId()))
                renderers.get(e.getTypeId()).render(g, e);
            else
                defaultRenderer.render(g, e);
        }
    }

    private EntityRenderer makeWallRenderer() {
        BasicEntityRenderer wall = new BasicEntityRenderer();
        wall.setShape(new Rectangle2D.Double(-75, -10, 150, 20));
        return wall;
    }

    private EntityRenderer makeMouseRenderer() {
        return new InputRenderer();
//        BasicEntityRenderer wall = new BasicEntityRenderer();
//        wall.setShape(new Ellipse2D.Double(-8, -8, 16, 16));
//        wall.setFillColor(new Color(0, 0, 0, 0));
//        wall.setStrokeColor(new Color(255, 0, 0, 127));
//        wall.setStroke(new BasicStroke(
//                4, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f,
//                new float[]{(float) Math.PI, (float) Math.PI}, 0.0f));
//        return wall;
    }

    private EntityRenderer makeLocustRenderer() {
//        BasicEntityRenderer locust = new BasicEntityRenderer();

        BasicEntityRenderer locust = new BasicEntityRenderer() {

            @Override
            public void render(final Graphics2D g, final Entity e) {
                final AffineTransform saveAT = g.getTransform();
                g.translate(e.getX(), e.getY());
                g.rotate(e.getOrientation());

                int alpha = (int)(255* e.getEnergy() / 100);
                if(alpha < 0) alpha = 0;
                if(alpha > 255) alpha = 255;
                final Color fill = new Color(getFillColor().getRed(),
                        getFillColor().getGreen(),
                        getFillColor().getBlue(),
                        alpha);

                g.setColor(fill);
                g.fill(getShape());
                g.setStroke(getStroke());
                g.setColor(getStrokeColor());
                g.draw(getShape());

                g.setTransform(saveAT);
            }
        };

        locust.setShape(new Triangle(0, 0, 20));
        locust.setFillColor(new Color(50, 100, 255, 255));
        return locust;

//
//        final List<BufferedImage> locusts = new ArrayList<BufferedImage>();
//        for (int i = 0; i < 12; i++) {
//            locusts.add(loadImage("res/insdrag" + i + ".png"));
//        }
//
//        final List<BufferedImage> blurred = new ArrayList<BufferedImage>();
//        int blur = 2;
//        int w = locusts.get(0).getWidth();
//        int h = locusts.get(0).getHeight();
//        for (int i = 0; i < 12; i++) {
//            BufferedImage tmp = new BufferedImage(w, h,
//                    BufferedImage.TYPE_INT_ARGB);
//            Graphics2D g = (Graphics2D) tmp.getGraphics();
//            g.setComposite(AlphaComposite.getInstance(
//                    AlphaComposite.SRC_OVER, 0.75f));
//            for (int j = 0; j < blur; j++) {
//                int k = (i + j) % 12;
//                g.drawImage(locusts.get(k), 0, 0, null);
//            }
//            blurred.add(tmp);
//        }
//
//        final BufferedImage shadow = loadImage("res/Particle.png");
//        final AnimationRenderer result = new AnimationRenderer();
//
//        for (int i = 0; i < 12; i++) {
//
//            BufferedImage buf = new BufferedImage(30, 30,
//                    BufferedImage.TYPE_INT_ARGB);
//
//            Graphics2D g = (Graphics2D) buf.getGraphics();
//
//            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
//                    0.5f));
//
//            g.drawImage(shadow, 0, 0, 30, 30, null);
//            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
//                    1f));
//            g.drawImage(blurred.get(i), 0, 0, 30, 30, null);
//
//            ColorConvertOp op = new ColorConvertOp(null);
//
//
//            result.addImage(buf);
//        }
//        result.setShowEnergy(true);
//        result.setShowId(true);
//        return result;

    }

    private EntityRenderer makeDeadLocustRenderer() {

        BasicEntityRenderer locust = new BasicEntityRenderer();
        locust.setShape(new Triangle(0, 0, 20));
        locust.setFillColor(new Color(255, 100, 50));
        return locust;
//
//        int i = (int) Math.floor(Math.random() * 12);
//        final BufferedImage deadLocust = loadImage("res/insdrag" + i + ".png");
//
//        final BufferedImage shadow = loadImage("res/Particle.png");
//
//        BufferedImage result = new BufferedImage(30, 30,
//                BufferedImage.TYPE_INT_ARGB);
//
//        Graphics2D g = (Graphics2D) result.getGraphics();
//
//        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
//                0.5f));
//
//        Shape s = new JaggedEllipse(15, 15, 20, 7);
//        g.setColor(Color.red);
//        g.fill(s);
//
//        g.drawImage(shadow, 0, 0, 30, 30, null);
//        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
//                1f));
//
//        g.drawImage(deadLocust, 0, 0, 30, 30, null);
//
//        ColorConvertOp op = new ColorConvertOp(null);
//
//        return new DeadLocustRenderer(result);
    }

    public static BufferedImage loadImage(
            String ref) {
        BufferedImage bimg = null;
        try {

            bimg = ImageIO.read(new File(ref));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bimg;
    }
}
